/**
 * 病友圈评论页面组件
 * 
 * 功能概述：
 * 1. 展示病友圈帖子的评论列表，支持层级评论展示
 * 2. 支持发表新评论功能
 * 3. 支持回复特定评论，实现二级评论结构
 * 4. 显示评论者头像、昵称、时间等信息
 * 5. 支持评论内容解析和格式化显示
 * 6. 提供评论发布和回复的用户交互
 * 
 * 技术特点：
 * - 使用 React Hooks 进行状态管理
 * - 集成 Ant Design Mobile 组件库
 * - 支持层级评论数据结构
 * - 完善的错误处理和用户反馈
 * - 响应式设计和移动端优化
 */

// 导入 React 核心功能：useEffect 用于副作用处理，useMemo 用于计算缓存，useState 用于状态管理
import { useEffect, useMemo, useState } from 'react'
// 导入 React Router 的导航钩子：useLocation 用于获取路由参数，useNavigate 用于页面跳转
import { useLocation, useNavigate } from 'react-router-dom'
// 导入 Ant Design Mobile 组件库：提供移动端UI组件
import { NavBar, Card, List, TextArea, Button, Toast } from 'antd-mobile'
// 导入 Ant Design Mobile 图标库：提供返回箭头图标
import { LeftOutline } from 'antd-mobile-icons'
// 导入用户头像组件：用于显示评论者头像
import UserAvatar from '../../components/UserAvatar'
// 导入自定义请求工具：封装了 axios，用于与后端 API 通信
import request from '../../api/request'
// 导入样式文件：定义组件的样式规则
import './index.css'

/**
 * 评论数据项接口
 * 
 * 定义了评论信息的完整数据结构，包含基本信息、统计数据、用户信息等
 * 这个接口用于统一处理评论数据的类型检查和数据操作
 * 
 * 字段说明：
 * - commentId: 评论唯一标识符，用于API调用和数据关联
 * - commentUserId: 评论用户ID，用于用户信息关联
 * - nickNmae: 用户昵称，显示在评论中（注意：字段名有拼写错误，应为nickName）
 * - headPic: 用户头像URL，用于显示用户头像
 * - content: 评论内容，支持回复格式的特殊标记
 * - supportNum: 点赞数量，显示评论的点赞次数
 * - opposeNum: 反对数量，显示评论的反对次数
 * - opinion: 观点标识，用于区分不同的观点类型
 * - whetherDoctor: 是否为医生评论，1表示医生，0表示普通用户
 * - commentTime: 评论时间戳（毫秒），用于时间显示和排序
 */
interface CommentItem {
  commentId: number      // 评论唯一标识符，用于API调用和数据关联
  commentUserId: number  // 评论用户ID，用于用户信息关联
  nickNmae: string      // 用户昵称，显示在评论中（注意：字段名有拼写错误）
  headPic: string       // 用户头像URL，用于显示用户头像
  content: string       // 评论内容，支持回复格式的特殊标记
  supportNum: number    // 点赞数量，显示评论的点赞次数
  opposeNum: number     // 反对数量，显示评论的反对次数
  opinion: number       // 观点标识，用于区分不同的观点类型
  whetherDoctor: number // 是否为医生评论，1表示医生，0表示普通用户
  commentTime: number   // 评论时间戳（毫秒），用于时间显示和排序
}

/**
 * 病友圈评论页面组件
 * 
 * 提供完整的评论功能，包括展示、发布、回复等
 * 支持层级评论、用户交互、内容解析等高级功能
 * 
 * 主要功能模块：
 * 1. 评论列表展示和层级结构
 * 2. 新评论发布功能
 * 3. 回复特定评论功能
 * 4. 评论内容解析和格式化
 * 5. 用户头像和昵称显示
 * 6. 时间显示和排序
 */
export default function Index() {
  // 获取当前路由位置信息，用于获取URL参数
  const location = useLocation()
  // 获取路由导航函数，用于页面跳转和返回操作
  const navigate = useNavigate()
  
  // ==================== 状态管理 ====================
  // 以下状态变量用于管理组件的各种状态和数据
  
  /**
   * 评论列表数据
   * 
   * 存储当前显示的所有评论信息，包含一级评论和二级评论
   * 数据类型为 CommentItem[]，包含所有评论的详细信息
   * 
   * 数据特点：
   * - 包含一级评论和二级评论
   * - 支持层级结构展示
   * - 动态更新和实时刷新
   */
  const [comments, setComments] = useState<CommentItem[]>([])
  
  /**
   * 加载状态标识
   * 
   * 标记当前是否正在加载评论数据，用于显示加载指示器
   * true 表示正在加载，false 表示加载完成
   * 
   * 使用场景：
   * - 初始页面加载时显示加载动画
   * - 防止用户重复触发数据请求
   * - 提供用户友好的加载反馈
   */
  const [loading, setLoading] = useState(false)
  
  /**
   * 评论内容
   * 
   * 存储用户正在输入的评论内容，用于评论发布功能
   * 空字符串表示未输入内容
   * 
   * 使用场景：
   * - 新评论输入
   * - 回复评论输入
   * - 内容验证和提交
   */
  const [content, setContent] = useState('')
  
  /**
   * 回复目标信息
   * 
   * 记录用户正在回复的评论信息，用于实现回复功能
   * null 表示不是回复模式，对象包含被回复评论的ID和昵称
   * 
   * 数据结构：
   * - id: 被回复评论的ID
   * - nick: 被回复用户的昵称
   * 
   * 使用场景：
   * - 回复特定评论
   * - 显示回复提示
   * - 生成回复格式的内容
   */
  const [replyTo, setReplyTo] = useState<{ id: number; nick: string } | null>(null)

  /**
   * 病友圈帖子ID
   * 
   * 从URL参数中提取的病友圈帖子ID，用于API请求
   * 使用 useMemo 缓存计算结果，避免重复计算
   * 
   * 提取逻辑：
   * - 从 location.search 中解析 URL 参数
   * - 获取 'id' 参数值
   * - 转换为数字类型
   * - undefined 表示参数不存在
   */
  const sickCircleId = useMemo(() => {
    const sp = new URLSearchParams(location.search)
    const id = sp.get('id')
    return id ? Number(id) : undefined
  }, [location.search])

  // ==================== API 数据获取函数 ====================
  // 以下函数负责从后端获取数据，处理API请求和响应
  
  /**
   * 获取评论列表数据
   * 
   * 从后端API获取指定病友圈帖子的评论列表
   * 这是评论页面的核心数据获取函数
   * 
   * API接口：/health/user/sickCircle/v1/findSickCircleCommentList
   * 
   * 请求参数：
   * - sickCircleId: 病友圈帖子ID，用于获取指定帖子的评论
   * - page: 页码，固定为1（当前实现只获取第一页）
   * - count: 每页数量，固定为20条
   * 
   * 数据处理：
   * - 数据格式验证
   * - 数组类型检查
   * - 错误处理和状态管理
   */
  const fetchComments = () => {
    // 如果没有帖子ID，直接返回
    if (!sickCircleId) return
    
    setLoading(true)
    request
      .get('/health/user/sickCircle/v1/findSickCircleCommentList', {
        params: { sickCircleId, page: 1, count: 20 }
      })
      .then((res) => {
        if (res.status === 200) {
          // 确保返回的数据是数组格式，防止数据类型错误
          setComments(Array.isArray(res.data.result) ? res.data.result : [])
        }
      })
      .finally(() => setLoading(false))
  }

  // ==================== 用户交互处理函数 ====================
  // 以下函数负责处理用户的交互操作
  
  /**
   * 发布评论
   * 
   * 处理用户发布评论的操作，包括内容验证、API调用、状态更新等
   * 这是评论页面的核心交互功能
   * 
   * 功能流程：
   * 1. 验证帖子ID和评论内容
   * 2. 根据是否为回复模式生成不同的内容格式
   * 3. 调用API发布评论
   * 4. 处理响应结果
   * 5. 更新本地状态
   * 6. 刷新评论列表
   * 7. 显示操作结果提示
   * 
   * 内容格式：
   * - 普通评论：直接使用用户输入的内容
   * - 回复评论：添加特殊标记 [cid:父评论ID] 回复@用户昵称：内容
   * 
   * 错误处理：
   * - 内容为空：提示用户输入内容
   * - API错误：显示具体错误信息
   * - 网络错误：显示网络错误提示
   */
  const publish = async () => {
    // 验证帖子ID是否存在
    if (!sickCircleId) return
    
    // 验证评论内容是否为空
    if (!content.trim()) {
      Toast.show({ content: '请输入评论内容' })
      return
    }
    
    try {
      // 根据是否为回复模式生成不同的内容格式
      let text: string
      if (replyTo) {
        // 回复模式：添加特殊标记，便于前端分组展示
        // [cid:父评论ID] 回复@用户昵称：实际内容
        text = `[cid:${replyTo.id}] 回复@${replyTo.nick}：${content.trim()}`
      } else {
        // 普通评论：直接使用用户输入的内容
        text = content.trim()
      }
      
      // 调用API发布评论
      const res = await request.post('/health/user/sickCircle/verify/v1/publishComment', {
        sickCircleId,
        content: text
      })
      
      // 处理API响应
      if (res.status === 200 && res.data?.status === '0000') {
        // 发布成功
        Toast.show({ content: '评论成功' })
        setContent('')        // 清空输入内容
        setReplyTo(null)      // 退出回复模式
        fetchComments()       // 刷新评论列表
      } else {
        // 发布失败，显示错误信息
        Toast.show({ content: res.data?.message || '评论失败' })
      }
    } catch (error) {
      // 网络错误或其他异常
      console.error('发布评论失败:', error)
      Toast.show({ content: '网络错误，稍后再试' })
    }
  }

  // ==================== 组件生命周期 ====================
  // 以下代码处理组件的生命周期事件
  
  /**
   * 组件初始化
   * 
   * 在组件挂载时或帖子ID变化时获取评论列表数据
   * 这是组件的初始化逻辑
   * 
   * 执行时机：
   * - 组件首次挂载时
   * - 帖子ID发生变化时
   * 
   * 依赖项：sickCircleId，确保帖子ID变化时重新获取数据
   */
  useEffect(() => {
    fetchComments()
  }, [sickCircleId])

  // ==================== 数据处理函数 ====================
  // 以下函数负责处理评论数据的解析和格式化
  
  /**
   * 解析回复评论内容
   * 
   * 解析包含回复格式的评论内容，提取回复信息
   * 支持两种格式：
   * 1. 新格式：[cid:父评论ID] 回复@用户昵称：内容
   * 2. 旧格式：回复@用户昵称：内容
   * 
   * 解析逻辑：
   * 1. 提取父评论ID（如果存在）
   * 2. 解析回复格式
   * 3. 提取被回复用户昵称和实际内容
   * 
   * @param text 需要解析的评论内容
   * @returns 解析结果对象，包含昵称、内容和父评论ID，null表示不是回复格式
   */
  const parseReply = (
    text: string
  ): { nick: string; body: string; cid?: number } | null => {
    // 提取父评论ID（新格式支持）
    let remain = text.trim()
    let cid: number | undefined
    
    // 匹配 [cid:数字] 格式的父评论ID
    const cidMatch = remain.match(/^\[cid:(\d+)\]\s*/)
    if (cidMatch) {
      cid = Number(cidMatch[1])
      remain = remain.slice(cidMatch[0].length)
    }
    
    // 匹配回复格式：回复@用户昵称：内容
    const match = remain.match(/^回复\s*@?([^：:]+)[：:]\s*(.*)$/)
    if (match) {
      return { 
        nick: match[1].trim(),  // 被回复用户昵称
        body: match[2],         // 实际回复内容
        cid                     // 父评论ID（如果存在）
      }
    }
    
    return null
  }

  /**
   * 按父评论ID分组二级评论
   * 
   * 将评论列表中的二级评论按父评论ID进行分组
   * 只处理包含 cid 标记的新格式回复，老数据作为独立项展示
   * 
   * 分组逻辑：
   * 1. 遍历所有评论
   * 2. 解析回复格式
   * 3. 提取父评论ID
   * 4. 按父评论ID分组
   * 5. 清理回复内容格式
   * 
   * @returns 按父评论ID分组的二级评论对象
   */
  const repliesByParent = comments.reduce<Record<string, CommentItem[]>>((acc, c) => {
    const parsed = parseReply(c.content)
    if (parsed && parsed.cid) {
      // 只处理包含 cid 的新格式回复
      const key = String(parsed.cid)
      const arr = acc[key] || (acc[key] = [])
      // 将解析后的内容（去除回复格式）添加到分组中
      arr.push({ ...c, content: parsed.body })
    }
    return acc
  }, {})

  // ==================== 组件渲染 ====================
  // 以下代码负责渲染组件的UI界面
  
  return (
    <div>
      {/* 头部导航栏：提供返回按钮和页面标题 */}
      <NavBar className="sticky-navbar" backArrow={<LeftOutline />} onBack={() => navigate(-1)}>
        病友圈评论
      </NavBar>

      {/* 评论列表卡片 */}
      <Card style={{ margin: 12 }}>
        <div style={{ fontWeight: 600, marginBottom: 8 }}>评论列表</div>
        <List>
          {loading ? (
            // 加载状态：显示加载提示
            <List.Item>加载中...</List.Item>
          ) : comments.length === 0 ? (
            // 空状态：显示无评论提示
            <List.Item>暂无评论</List.Item>
          ) : (
            // 评论列表：展示所有评论
            comments
              // 过滤出顶层评论：原生顶层评论 + 早期无 cid 的回复评论
              .filter((c) => {
                const p = parseReply(c.content)
                return !p || !p.cid  // 不是回复格式，或者没有 cid 标记
              })
              .map((c) => (
                <List.Item
                  key={c.commentId}
                  // 用户头像：支持匿名显示
                  prefix={<UserAvatar src={c.headPic} size={36} isAnonymous={!c.headPic || !c.nickNmae} className="user-avatar" />}
                  // 评论时间：格式化为本地时间
                  description={new Date(c.commentTime).toLocaleString()}
                  // 回复按钮：点击进入回复模式
                  extra={<Button size='mini' onClick={() => setReplyTo({ id: c.commentId, nick: c.nickNmae })}>回复</Button>}
                >
                  {/* 用户昵称：支持匿名显示 */}
                  <div style={{ fontWeight: 500 }}>{c.nickNmae || '匿名'}</div>
                  
                  {/* 评论内容：支持回复格式显示 */}
                  {(() => {
                    const p = parseReply(c.content)
                    if (p && !p.cid) {
                      // 旧格式回复：显示回复格式
                      return (
                        <div style={{ color: '#666', marginTop: 4 }}>
                          <span style={{ color: '#1677ff' }}>@{p.nick}：</span>
                          {p.body}
                        </div>
                      )
                    }
                    // 普通评论：直接显示内容
                    return <div style={{ color: '#666', marginTop: 4 }}>{c.content}</div>
                  })()}
                  
                  {/* 二级评论：显示回复该评论的所有二级评论 */}
                  {repliesByParent[String(c.commentId)] && (
                    <div style={{ marginTop: 8, paddingLeft: 10, borderLeft: '2px solid #f0f0f0', display: 'flex', flexDirection: 'column', gap: 8 }}>
                      {repliesByParent[String(c.commentId)].map((r) => (
                        <div key={r.commentId} style={{ display: 'flex', gap: 8 }}>
                          {/* 二级评论用户头像 */}
                          <UserAvatar src={r.headPic} size={24} isAnonymous={!r.headPic || !r.nickNmae} className="user-avatar" />
                          <div style={{ flex: 1 }}>
                            {/* 二级评论头部：昵称和时间 */}
                            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                              <span style={{ fontWeight: 500, fontSize: 12 }}>{r.nickNmae || '匿名'}</span>
                              <span style={{ color: '#999', fontSize: 11 }}>{new Date(r.commentTime).toLocaleString()}</span>
                            </div>
                            {/* 二级评论内容 */}
                            <div style={{ color: '#666', fontSize: 12, marginTop: 2 }}>{r.content}</div>
                          </div>
                        </div>
                      ))}
                    </div>
                  )}
                </List.Item>
              ))
          )}
        </List>
      </Card>

      {/* 评论输入卡片 */}
      <Card style={{ margin: 12 }}>
        <div style={{ marginBottom: 8, fontWeight: 600 }}>写评论</div>
        
        {/* 回复提示：当处于回复模式时显示 */}
        {replyTo && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, fontSize: 12, color: '#666' }}>
            正在回复：<span style={{ color: '#1677ff' }}>@{replyTo.nick}</span>
            <Button size='mini' onClick={() => setReplyTo(null)}>取消回复</Button>
          </div>
        )}
        
        {/* 评论输入框：支持多行输入 */}
        <TextArea 
          value={content} 
          onChange={setContent} 
          rows={4} 
          placeholder={replyTo ? `回复 @${replyTo.nick}…` : '说点什么吧…'} 
        />
        
        {/* 发送按钮：发布评论 */}
        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 10 }}>
          <Button color='primary' onClick={publish}>发送</Button>
        </div>
      </Card>
    </div>
  )
}


